package project;

import java.util.ArrayList;
import java.util.List;

public class GameState implements GameStateIF {
 
	protected int[][] grid = new int[17][17];
	protected PlayerState[] players = new PlayerState[2];
	protected int currPlayer;

   	private static final String w[] = {"   ", "---", "|", " X ", " O ", "+"};
	protected static final int EMPTY = 0;
	protected static final int HORIZONTAL = 1;
	protected static final int VERTICAL = 2;
	protected static final int PLAYER0 = 3;
	protected static final int PLAYER1 = 4;
	protected static final int WALLCENTRE = 5;
	protected static final int GAMENOTOVER = -1;
	
	GameState() {
		initialise();
	}
	
	private void initialise() {
	   	players[0] = new PlayerState(4, 0, 10);
	   	players[1] = new PlayerState(4, 8, 10);
	   	currPlayer = 1;
	}
    
	public GameState clone() {
		
    	GameState copy = new GameState();
    	int i, j;
    	
    	for (i = 0; i < 17; i++)
    		for (j = 0; j < 17; j++)
    			copy.grid[i][j] = grid[i][j];
    	
    	copy.players[0] = players[0].clone();
    	copy.players[1] = players[1].clone();
    	copy.currPlayer = currPlayer;
    	
    	return copy;
	}
    
	public GameState applyMove(Move move) {
		
	   	int x, y;
		if (move instanceof PawnMove) {
	    	x = move.getX();
	    	y = move.getY();
	    	players[move.player].setX(x);
	    	players[move.player].setY(y);
		} else {
	    	x = move.getX();
	    	y = move.getY();
           	grid[x*2+1][y*2+1] = WALLCENTRE;
	       	if (((WallMove) move).isHorizontal) {
	           	grid[x*2][y*2+1] = HORIZONTAL;
	           	grid[x*2+2][y*2+1] = HORIZONTAL;
	       	} else {
	           	grid[x*2+1][y*2] = VERTICAL;
	           	grid[x*2+1][y*2+2] = VERTICAL;
	       	}
	       	players[move.player].setWallCount(players[move.player].getWallCount()-1);
		}
		currPlayer = 1 - currPlayer;
		return this;
	}
   
	public PlayerState[] getPlayers() {
    	return players;
	}
   
	public int[][] getGrid() {
    	return grid;
	}
 
	public String toString() {
		
	   	StringBuilder ret = new StringBuilder();
	   	
	   	grid[players[0].getX()*2][players[0].getY()*2] = PLAYER0;
	   	grid[players[1].getX()*2][players[1].getY()*2] = PLAYER1;
	   	
	   	ret.append("    ");
	   	for (int a = 0; a < 17; a++) {
	       	if (a%2 == 0) {
	           	ret.append((char)(a/2+'a'));
	           	ret.append("  ");
	       	} else {
	           	ret.append(" ");
	       	}
	   	}
	   	
	   	ret.append("\n");
	   	for (int b = -1; b <= 17; ++b) {
	   		
	       	if (b%2 == 0)
	           	ret.append((char)(b/2+'1'));
	       	else
	           	ret.append(" ");
	       	
	       	ret.append(" ");
	       	for (int a = -1; a <= 17; ++a) {
	       		ret.append(getPrint(a, b));
	       	}
	       	ret.append("\n");
	   	}
	   	
	   	grid[players[0].getX()*2][players[0].getY()*2] = EMPTY;
	   	grid[players[1].getX()*2][players[1].getY()*2] = EMPTY;
	   	
	   	ret.append("Player X has ");
	   	ret.append(players[0].getWallCount());
	   	ret.append(" walls left.\nPlayer O has ");
	   	ret.append(players[1].getWallCount());
	   	ret.append(" walls left.\n");
	   	if (gameOver() == GAMENOTOVER) {
	   		ret.append("It is player ");
		   	ret.append(currPlayer == 0? 'X': 'O');
		   	ret.append("'s turn.\n");
	   	} else {
	   		ret.append("Player ");
		   	ret.append(gameOver() == 0? 'X': 'O');
		   	ret.append(" has won the game\n");
	   	}
	   	
	   	return ret.toString();
	}
	
	private String getPrint(int x, int y) {
		
		if (x < 0)	//If this is the left border
			return (y % 2 == 0) ? "|" : "+";
		if (y < 0)	//If this is the top border
			return (x % 2 == 0) ? "---" : "+";
		if (x >= 17)	//If this is the right border
			return (y % 2 == 0) ? "|" : "+";
		if (y >= 17)	//If this is the bottom border
			return (x % 2 == 0) ? "---" : "+";
		
		if (grid[x][y] == EMPTY)	//Print empty space
			return (x % 2 == 1) ? (y % 2 == 1) ? "." : " " : w[EMPTY];	//Odd columns are thin, even are thick
		else
			return w[grid[x][y]];
	}
	
	public List<Move> validMoves() {
		
		List<Move> ans = new ArrayList<Move>();
		int i, j;
		StringBuilder temp;
		Move move;
		
		//Try every move in a 5x5 square around the current player
		for (i = players[currPlayer].getX()-2; i <= players[currPlayer].getX()+2; i++) {
			for (j = players[currPlayer].getY()-2; j <= players[currPlayer].getY()+2; j++) {
				temp = new StringBuilder();
				temp.append((char)('a'+i));
				temp.append((char)('1'+j));
				move = Move.newMove(temp.toString(), currPlayer);
				if (Validity.isValid(move, this))
					ans.add(move);
			}
		}
		
		for (i = 0; i < 8; i++) {
			for (j = 0; j < 8; j++) {
				temp = new StringBuilder();
				temp.append((char)('a'+i));
				temp.append((char)('1'+j));
				temp.append("h");
				move = Move.newMove(temp.toString(), currPlayer);
				if (Validity.isValid(move, this))
					ans.add(move);
				
				temp = new StringBuilder();
				temp.append((char)('a'+i));
				temp.append((char)('1'+j));
				temp.append("v");
				move = Move.newMove(temp.toString(), currPlayer);
				if (Validity.isValid(move, this))
					ans.add(move);
			}
		}
		
		return ans;
	}
	
	public int gameOver() {
		if (players[0].getY() == 8)
			return 0;
		if (players[1].getY() == 0)
			return 1;
		return GAMENOTOVER;
	}
}